home *** CD-ROM | disk | FTP | other *** search
/ Deutsche Edition 1 / Deutsche Edition 1.iso / amok / 051-060 / amok56 / turbofiles_v2.0 / (turbo)files.dok < prev    next >
Text File  |  1993-11-04  |  17KB  |  332 lines

  1. DEFINITION (Turbo)Files V2.0;
  2.  
  3. CONST (* Der Modus für Open() *)
  4.   newFile = TRUE;
  5.   oldFile = FALSE;
  6.  
  7. CONST (* mögliche Werte von f.res *)
  8.   done*        = 0;  (* alles ok *)
  9.   notdone*     = 1;  (* unbekannter Fehler *)
  10.   notOpen*     = 2;  (* File nicht geoeffnet oder wieder geschlossen *)
  11.   openError    = 3;  (* Fehler beim Öffnen der Datei *)
  12.   readError    = 4;  (* Lesefehler, Diskette kaputt *)
  13.   writeError   = 5;  (* Schreibfehler, Diskette kaputt, Disk voll *)
  14.   seekError    = 6;  (* SetPos() ergab Position außerhalb der Datei *)
  15.   endOfFile    = 7;  (* Dateiende beim Lesen überschritten *)
  16.   outOfMem     = 8;  (* Zu wenig Speicher, Puffer bei Open() zu groß *)
  17.   notExists    = 9;  (* Datei existiert nicht *)
  18.  
  19. CONST (* Der Modus von SetPos() *)
  20.   beginning = Dos.beginning;
  21.   current   = Dos.current;
  22.   end       = Dos.end;
  23.  
  24. TYPE
  25.   File = RECORD
  26.     res : SHORTINT;
  27.   END;
  28.  
  29. PROCEDURE Open(VAR f: File; name: ARRAY OF CHAR;
  30.                bufferSize: LONGINT; new: BOOLEAN): BOOLEAN;
  31. PROCEDURE ReadBytes (VAR f:File; adr: Exec.ADDRESS; len: LONGINT): LONGINT;
  32. PROCEDURE WriteBytes(VAR f:File; adr: Exec.ADDRESS; len: LONGINT): BOOLEAN;
  33. PROCEDURE ReadChar (VAR f: File; VAR ch: CHAR): BOOLEAN;
  34. PROCEDURE WriteChar(VAR f: File;     ch: CHAR): BOOLEAN;
  35. PROCEDURE Read (VAR f: File; VAR block: ARRAY OF BYTE): BOOLEAN;
  36. PROCEDURE Write(VAR f: File;     block: ARRAY OF BYTE): BOOLEAN;
  37. PROCEDURE ReadString (VAR f: File; VAR str: ARRAY OF CHAR): INTEGER;
  38. PROCEDURE WriteString(VAR f: File;     str: ARRAY OF CHAR): BOOLEAN;
  39. PROCEDURE WriteLn(VAR f: File): BOOLEAN;
  40. PROCEDURE Size(VAR f: File): LONGINT;
  41. PROCEDURE GetPos(VAR f: File): LONGINT;
  42. PROCEDURE SetPos(VAR f: File; offset: LONGINT; mode: LONGINT): BOOLEAN;
  43. PROCEDURE Search(VAR f: File; str: ARRAY OF BYTE; len: INTEGER): LONGINT;
  44. PROCEDURE Close(VAR f: File):BOOLEAN;
  45.  
  46. PROCEDURE Code(fileName, codeWord: ARRAY OF CHAR; decode: BOOLEAN):BOOLEAN;
  47. PROCEDURE DeleteFile(name: ARRAY OF CHAR): BOOLEAN;
  48. PROCEDURE Exists(name: ARRAY OF CHAR; VAR size: LONGINT): BOOLEAN;
  49.  
  50. END (Turbo)Files.
  51.  
  52. Dieses Modul vereinfacht und beschleunigt das Arbeiten mit Datein. Die Modu­
  53. le  Files und TurboFiles sind vom Verhalten her identisch. In dem Modul Tur­
  54. boFiles sind allerdings einige Oberon-Prozeduren durch  Assembleräquivalente
  55. ersetzt   worden.  Dadurch  ergibt  sich  eine  merkliche  Geschwindigkeits­
  56. steigerung, und der Programmcode wird fast 1 kByte kleiner. Ursprünglich war
  57. Files bzw. TurboFiles als Ersatz für das FileSystem von M2Amiga gedacht. Ich
  58. habe die Module nun nach Oberon übertragen und den Assemblerteil stark über­
  59. arbeitet. Der gesamte Assemblertext befindet sich jetzt  in  dem  File  Tur­
  60. boFiles.asm  und kann mit dem FD-Assembler A68k assembliert werden. Man kann
  61. das dadurch erzeugte File TurboFiles.o dann einfach mit dem CLI-Befehl  JOIN
  62. an  TurboFiles.obj(s)  anhängen  und das Modul dann wie ein normales Oberon-
  63. Modul benutzen. Die Assemblerprozeduren benutzen keine  globalen  statischen
  64. Variablen und sind deshalb reentrant. Deshalb können Programme, die TurboFi­
  65. les  benutzen und mit dem kleinen Datenmodell compiliert sind, weiterhin wie
  66. gewohnt im CLI mit  ARP.ARES  oder  RESIDENT  installiert  werden  und  auch
  67. gleichzeitig mehrmals gestartet werden. Der Assemblerteil macht sich also in
  68. keiner  Weise negativ bemerkbar. Zudem beachten jetzt alle Assemblerprozedu­
  69. ren die Amiga-Dos Registerkonvention, d.h. es werden von den Prozeduren  nur
  70. die  Register  D0,  D1,  A0  und  A1 verändert. Deshalb wird es auch mit zu­
  71. kümpftigen Compilerversionen keine  Schwierigkeiten  geben.  Die  Prozeduren
  72. sind  von  der  Namensgebung  und  dem  Verhalten den Prozeduren des Oberon-
  73. FileSystem  sehr  ähnlich,  aus  der  Entwicklungsgeschichte   und    meinem
  74. persönlichen Geschmack ergeben sich allerdings einige Unterschiede. So halte
  75. ich  den  Namen ReadBytes() für treffender als ReadBlock(), und ich halte es
  76. z.B. für sinnvoll, daß ReadBytes() statt eines Wertes vom Typ BOOLEAN lieber
  77. die Anzahl der gelesenen Bytes zurückgibt.
  78.  
  79. Was ist nun der Vorteil von Files bzw. TurboFiles gegenüber dem Oberon-File­
  80. System? Zunächst einmal ist (Turbo)Files FD-Software, also  frei  kopierbar.
  81. Es  darf  also  auch von Personen benutzt werden, welche nur die Demoversion
  82. des Oberoncompilers besitzen. Weiterhin hat (Turbo)Files einige Fähigkeiten,
  83. die FileSystem nicht besitzt. So kann gleichzeitig aus einer  Datei  gelesen
  84. und  in  sie  geschrieben werden. (Diesem Modus unterstützt das Oberon-File-
  85. System ab der Compilerversion 2.0 allerdings auch. )    Außerdem  existieren
  86. die Prozeduren Search() und Code() zum Durchsuchen und Codieren einer Datei.
  87. Der Hauptvorteil ist aber die größere Geschwindigkeit von TurboFiles. Wärend
  88. sich  Files  und  FileSystem  in der Geschwindigkeit kaum unterscheiden, ist
  89. TurboFiles insbesondere beim Lesen und Schreiben  von  kleinen  Datenblöcken
  90. merklich  schneller.  So  dauert  das  zeichenweise  Lesen  einer  100 kByte
  91. großen  Datei  von  RAM:  mit  FileSystem.ReadChar()  ca.  8  Sekunden,  mit
  92. TurboFiles.ReadChar)_  aber nur 4 Sekunden. Beim Datenaustausch zur Diskette
  93. ist der relative Geschwindigkeitsgewinn  natürlich  kleiner,  da  TurboFiles
  94. nicht  das  langsame  Diskettenlaufwerk  beschleunigen  kann.  Ebenso bringt
  95. TurboFiles nicht  viel,  wenn  man  große  Datenblöcke,  etwa  Strings  oder
  96. Records,  einliest  oder  in eine Datei schreibt. TurboFiles lohnt sich also
  97. am meistem, wenn man Daten in sehr kleinen Portionen (Bytes,  Integers  ...)
  98. von  einem  schnellen physikalischen Gerät (Ram-Disk, Festplatte) liest oder
  99. dorthin schreibt. Da TurboFiles aber keinerlei Nachteile hat, sollte man  es
  100. am besten immer benutzen!
  101.  
  102. Hier zur Motivation ein Geschwindigkeitsvergleich von TurboFiles und dem
  103. Oberon-FileSystem:
  104.  
  105. (Der  Vergleich  wurde  mit  dem beiligenden Programm SpeedCheck erzeugt. Es
  106. wurde von RAM: eine 139 kByte große Datei gelesen  bzw.  eine  gleich  große
  107. Datei erzeugt. TurboFiles benutzte wie FileSystem einen Puffer von 1024 kBy­
  108. te. Wie man sieht ist TurboFiles ca. doppelt so schnell wie FileSystem.)
  109.  
  110. TurboFiles vs. FileSystem
  111. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  112. Reading single Characters using ReadChar()
  113. TurboFiles.ReadChar():              5,58
  114. FileSystem.ReadChar():             13,56
  115.  
  116. Reading LONGINTs using ReadBytes()=ReadBlock()
  117. TurboFiles.ReadBytes():             3,18
  118. FileSystem.ReadBlock():            10,40
  119.  
  120. Reading LONGINTs using Read()
  121. TurboFiles.Read():                  3,88
  122. FileSystem.Read():                  9,76
  123.  
  124. Writing single Characters using WriteChar()
  125. TurboFiles.WriteChar():             8,46
  126. FileSystem.WriteChar():            16,90
  127.  
  128. Writing LONGINTSs using WriteBytes()=WriteBlock()
  129. TurboFiles.WriteBytes():            4,02
  130. FileSystem.WriteBlock():           11,02
  131.  
  132. Writing LONGINTSs using Write()
  133. TurboFiles.Write():                 4,58
  134. FileSystem.Write():                12,36
  135.  
  136. Nun  zu  den  Prozeduren  des  Moduls:  Die Prozeduren, welche ein boolsches
  137. Ergebnis liefern, waren immer erfolgreich, wenn sie TRUE zurückgeben.  Ande­
  138. renfalls  kann  man das Feld f.res der File-Variablen abfragen, um genaueres
  139. über die Fehlerursache zu erfahren. Das Feld f.res kann einen der  folgenden
  140. Werte annehmen:
  141.  
  142. CONST (* mögliche Werte von f.res *)
  143.   done*        = 0;  (* alles ok *)
  144.   notdone*     = 1;  (* unbekannter Fehler *)
  145.   notOpen*     = 2;  (* File nicht geoeffnet oder wieder geschlossen *)
  146.   openError    = 3;  (* Fehler beim Öffnen der Datei *)
  147.   readError    = 4;  (* Lesefehler, Diskette kaputt *)
  148.   writeError   = 5;  (* Schreibfehler, Diskette kaputt, Disk voll *)
  149.   seekError    = 6;  (* SetPos() ergab Position außerhalb der Datei *)
  150.   endOfFile    = 7;  (* Dateiende beim Lesen überschritten *)
  151.   outOfMem     = 8;  (* Zu wenig Speicher, Puffer bei Open() zu groß *)
  152.   notExists    = 9;  (* Datei existiert nicht *)
  153.  
  154. Solange kein Fehler aufgetreten ist, hat f.res den Wert done. Tritt ein Feh­
  155. ler  auf,  beispielsweise  daß  versucht wurde, über das Dateiende hinaus zu
  156. lesen, so setzt die entsprechende Prozedur f.res  auf  einen  Wert  ungleich
  157. done. In diesem Fall werden alle nachfolgenden Prozeduraufrufe außer Close()
  158. ignoriert.
  159.  
  160. PROCEDURE Open(VAR f: File; name: ARRAY OF CHAR;
  161.                 bufferSize: LONGINT; new: BOOLEAN): BOOLEAN;
  162.  
  163. Bevor  man  die  folgenden  Prozeduren  zur Bearbeitung einer Datei benutzen
  164. kann, muß diese durch Open() geöffnet werden. Open()  öffnet  die  Dos-Datei
  165. und initialisiert die File-Variable. name ist der Name der Datei und muß ein
  166. gültiger  Amiga-Dos Filename sein, wie etwas "Ram:Text1" oder "PRT:" . Durch
  167. bufferSize wird angegeben, wie groß der beim Lesen  und  Schreiben  benutzte
  168. Puffer  sein  soll. In der Regel ist 1 kByte ausreichend, beim Schreiben auf
  169. Diskette ist allerdings ein größerer  Puffer  von  beispielsweise  10  kByte
  170. vorteilhaft.  Ist  new=TRUE, so wird eine neue Datei angelegt, ist new=FALSE
  171. wird versucht, eine existierende Datei zu öffnen.
  172.  
  173. Die Prozeduren zum Lesen von Daten:
  174.  
  175. PROCEDURE Read(VAR f: File; VAR block: ARRAY OF BYTE): BOOLEAN;
  176.  
  177. Liest  LEN(block)  Bytes aus der Datei und speichert sie in block. block ist
  178. kompatibel zu allen Datentypen, man kann mit Read() also sowohl Records  als
  179. auch INTEGER- oder REAL-Zahlen einlesen.
  180.  
  181. PROCEDURE ReadChar(VAR f: File; VAR ch: BYTE): BOOLEAN;
  182.  
  183. Liest  ein  einzelnes Zeichen bzw. BYTE aus der Datei. Statt ReadChar() kann
  184. man auch Read() verwenden, TurboFiles.ReadChar() ist aber wesentlich schnel­
  185. ler.
  186.  
  187. PROCEDURE ReadString(VAR f: File; VAR str: ARRAY OF CHAR): INTEGER;
  188.  
  189. Liest mit Hilfe von ReadChar() eine Zeichenkette aus der Datei. Als  String­
  190. ende  wird  ein 0X oder ein LineFeed (0AX) angesehen.  Maximal werden jedoch
  191. LEN(str) Zeichen gelesen. Als Resultat wird die Länge des gelesenen  Strings
  192. zurückgegeben.
  193.  
  194. PROCEDURE ReadBytes(VAR f: File; adr: Exec.ADDRESS; len: LONGINT): LONGINT;
  195.  
  196. ReadBytes()  ist (da der Datentyp Exec.ADDRESS benutzt wird) eine sogenannte
  197. Low-Level-Prozedur und sollte deshalb nur benutzt werden,  wenn  dies  unum­
  198. gänglich  ist,  wenn  also z.B. Daten an eine ganz bestimmte Adresse geladen
  199. werden müssen. adr gibt an, wohin die Daten geladen werden sollen,  und  len
  200. gibt  an, wie viele Bytes gelesen werden sollen. Als Resultat erhält man die
  201. Anzahl Bytes, die gelesen werden konnten. Trat kein Fehler auf, so ist  die­
  202. ses  Resultat gleich len; wurde aber z.B. versucht über das Dateiende hinaus
  203. zu lesen, so ist das Resultat kleiner als len und f.res=endOfFile.
  204.  
  205. Die Prozeduren zum Schreiben von Daten in eine Datei:
  206.  
  207. PROCEDURE Write(VAR f: File; block: ARRAY OF BYTE): BOOLEAN;
  208.  
  209. Schreibt LEN(block) Bytes in die Datei. Dem Parameter block können  beliebi­
  210. ge  Datentypen zugewiesen werden, also beispielsweise Records oder auch LON­
  211. GREAL-Zahlen.
  212.  
  213. PROCEDURE WriteChar(VAR f: File; ch: BYTE): BOOLEAN;
  214.  
  215. Schreibt ein einzelnes Zeichen bzw. Byte in die Datei. Man kann auch Write()
  216. benutzen, TurboFiles.WriteChar() ist aber deutlich schneller.
  217.  
  218. PROCEDURE WriteString(VAR f: File; str: ARRAY OF CHAR): BOOLEAN;
  219.  
  220. Schreibt die Zeichenkette str in die  Datei.  Die  Zeichenkette  wird  NICHT
  221. durch ein LineFeed abgeschlossen. Soll der nächste String in eine neue Zeile
  222. geschrieben  werden, so muß man vorher WriteChar(f,ASCII.lf) oder WriteLn(f)
  223. aufrufen.
  224.  
  225. PROCEDURE WriteBytes(VAR f: File; adr: Exec.ADDRESS; len: LONGINT): BOOLEAN;
  226.  
  227. Dies ist wiederum eine Low-Level Prozedur. Sie sollte  nur  benutzt  werden,
  228. wenn  die  anderen  Schreibprozeduren nicht einsetzbar sind. adr gibt an, wo
  229. die Daten stehen, welche in die Datei geschrieben  werden  sollen,  und  len
  230. gibt an, wie viele Bytes geschrieben werden sollen.
  231.  
  232. Nun zu den Prozeduren GetPos, SetPos und Size:
  233.  
  234. PROCEDURE GetPos(VAR f: File): LONGINT;
  235.  
  236. GetPos()  liefert die momentane Position in der Datei, gemessen vom Dateian­
  237. fang. Sollte bei vorherigen Dateioperationen bereits ein Fehler  aufgetreten
  238. sein,  und  deshalb f.res einen Wert ungleich done haben, so ergibt GetPos()
  239. als Resultat den Wert -1.
  240.  
  241. PROCEDURE SetPos(VAR f: File; offset: LONGINT; mode: LONGINT): BOOLEAN;
  242.  
  243. Mit dieser Prozedur kann man an eine beliebige Stelle innerhalb einer  Datei
  244. springen.  offset  bestimmt  die  neue Position. Ist mode=beginning, so wird
  245. offset vom Anfang der Datei aus gemessen, ist  mode=end,  so  vom  Ende  der
  246. Datei  aus.  Ist  mode=current, so wird die aktuelle Position um offset ver­
  247. schoben; dabei verschiebt ein positiver Wert die Position zum Dateiende, ein
  248. negativer zum Dateianfang. Wird versucht, eine Position außerhalb der Datei­
  249. grenzen anzuwählen, so wird f.res auf seekError gesetzt und FALSE  zurückge­
  250. geben.
  251.  
  252. PROCEDURE Size(VAr f: File): LONGINT;
  253.  
  254. Size() liefert die  momentane  Dateigröße  in  Bytes.  Hat  f.res einen Wert
  255. ungleich done, so wird -1 zurückgegeben.
  256.  
  257. PROCEDURE Search(VAR f: File; str: ARRAY OF BYTE; len: INTEGER): LONGINT;
  258.  
  259. Sucht in der Datei ab der momentanen Position nach str, wobei nur die ersten
  260. len Bytes von str berücksichtigt werden. Wird str gefunden, so wird die  ak­
  261. tuelle Position auf diese Stelle gesetzt und diese Position wird zurückgege­
  262. ben.  Wird  str nicht gefunden, so wird -1 zurückgegeben und f.res hat einen
  263. Wert ungleich done.
  264.  
  265. PROCEDURE Close(VAR f: File):BOOLEAN;
  266.  
  267. Schließt eine offene Datei. Sobald man mit einer Datei nicht  mehr  arbeiten
  268. will,  sollte  man sie mit Close() schliessen. Wird das Programm durch einen
  269. Laufzeitfehler oder Control-C abgebrochen, so wird die Dos-Datei automatisch
  270. geschlossen, allerdings wird vorher der eventuell  durch  Schreiboperationen
  271. veränderte  Puffer  nicht  in  die  Dos-Datei  abgespeichert. Ist  die Datei
  272. bereits geschlossen, oder war das Öffnen nicht  erfolgreich, so gibt Close()
  273. den Wert  FALSE  zurück, ohne  irgendetwas zu tun. Das  Gleiche tut  Close(),
  274. wenn f.res den  Wert  notOpen hat.  Nachdem die File-Variable  durch  Open()
  275. initialisiert  worden  ist,  kann man  jederzeit  Close()  aufrufen, egal ob
  276. Open()  erfolgreich war oder nicht. Setzt man f.res am  Beginn des Programms
  277. auf den Wert notOpen, so ist sichergestellt, daß ein (durch  einen Programm-
  278. abbruch  verursachtes)  Close()  nicht  mit  einer  uninitiallisierten File-
  279. Variablen arbeitet.
  280.  
  281.  
  282. Die folgenden drei Prozeduren dürfen nur auf  geschlossene  bzw.  gar  nicht
  283. erst geöffnete Dateien angewendet werden:
  284.  
  285. PROCEDURE DeleteFile(name: ARRAY OF CHAR): BOOLEAN;
  286.  
  287. Löscht eine Datei. Synonym für Dos.Delete().
  288.  
  289. PROCEDURE Exists(name: ARRAY OF CHAR; VAR size: LONGINT): BOOLEAN;
  290.  
  291. Exists()  überprüft, ob eine Datei bzw. ein Verzeichnis existiert. Existiert
  292. die Datei bzw. das Directory, wird  TRUE  zurückgegeben,anderenfalls  FALSE.
  293. Handelt es sich um eine Datei, enthält size deren Größe in Bytes. Ist es ein
  294. Verzeichnis, wird size auf den Wert -1 gesetzt.
  295.  
  296. PROCEDURE Code(fileName, codeWord: ARRAY OF CHAR; decode: BOOLEAN):BOOLEAN;
  297.  
  298. Diese  Prozedur  dient  zum  Codieren von beliebigen Files. codeWord ist ein
  299. beliebiger String, der alle Zeichen bis auf 0X enthalten darf und nicht län­
  300. ger als 126 Zeichen sein sollte. decode gibt an ob die  Datei  codiert  oder
  301. decodiert  werden  soll.  Man kann jede beliebige Datei codieren. Danach ist
  302. sie solange unlesbar und unbrauchbar, bis sie wieder mit dem gleichen  Code­
  303. wort  decodiert  worden  ist. Die codierte Datei hat die selbe Größe und den
  304. selben Namen wie das Original, d.h. das Original wird überschrieben!
  305.  
  306.  
  307. Zum Schluß noch einige allgemeine Bemerkungen:
  308.  
  309. Wie  schon  gesagt,  werden  alle  Prozeduraufrufe  außer Close() ignoriert,
  310. wenn f.res einen Wert ungleich done hat. In der Regel ist  dann  ein  Fehler
  311. aufgetreten und man wird die Datei schließen. In einigen Fällen kann es aber
  312. sinnvoll  sein,  die  Datei  weiter zu bearbeiten, beispielsweise wenn durch
  313. Search() oder Read() das Dateiende erreicht worden ist. Man kann dann  f.res
  314. auf done zurücksetzen und versuchen die Datei weiter zu bearbeiten.
  315.  
  316. Das optimierende Linken des Assemblerteils von TurboFiles  funktioniert mom­
  317. entan nicht. Der Assemblerteil besteht aus 9 Prozeduren, welche sich alle in
  318. einem File befinden. Mit dem FD-Assembler A68k ist es  mir  nicht  gelungen,
  319. für jede Prozedur einen separaten Unit-HUNK zu erzeugen. Die neun Prozeduren
  320. befinden  sich  daher alle in einem einzigen HUNK. Wird nun eine dieser neun
  321. Prozeduren benutzt, so linkt BLink den ganzen Hunk mit allen  neun  Prozedu­
  322. ren  zum Hauptprogramm dazu. Das ist zwar nicht weiter tragisch, da die neun
  323. Prozeduren zusammen nur ca. 1 kByte groß sind, aber es ist doch ein  kleiner
  324. Schönheitsfehler.
  325.  
  326. TurboFiles V2.0 wurde auf einen A1000 mit KS und WB 1.3 entwickelt und ge-
  327. testet, sollte aber auf jeden Amiga laufen.
  328.  
  329. Stefan Salewski,  9. Juni 1991
  330.  
  331.  
  332.